(() => {
    /*
        秘密命令, 类似于GTA系列游戏中的秘籍, 在页面中敲击键盘使用
    */
   
    // panel在多久自动关闭
    const PANEL_HIDE_TIMEOUT = 1000;
    // panel使用的标签
    const PANEL_TAG = 'div';
   
    /**
     * 命令显示面板 控制器
     */
    const PanelControl = (function() {
        let panel = null;
        /**
         * 将panel安装到页面中
         */
        function install() {
            if (panel == null) {
                panel = document.createElement(PANEL_TAG);
                Object.assign(panel.style, {
                    position: 'fixed',
                    zIndex: '99999',
                    top: '20px',
                    right: '20px',
                    width: 'auto',
                    fontSize: '28px',
                    letterSpacing: '4px',
                    backgroundColor: '#fff',
                    border: '1px solid darkgray',
                    margin: '0px',
                    padding: '20px'
                });
                document.body.append(panel);
            }
        }
        /**
         * 将panel从页面中卸载
         */
        function uninstall() {
            panel?.remove();
            panel = null;
        }

        // panel显示状态
        let panelVisible = false;
        // panel延迟隐藏的timeout句柄
        let timeoutHandle = null;
        /**
         * 延迟隐藏panel
         */
        function hide() {
            if (panel === null) {
                return;
            }
            if (timeoutHandle) {
                clearTimeout(timeoutHandle);
            }
            timeoutHandle = setTimeout(function() {
                timeoutHandle = null;
                panel.style.display = 'none';
                panelVisible = false;
            }, PANEL_HIDE_TIMEOUT);
        }
        /**
         * 显示panel
         * @param {string} content panel内的文本内容 
         */
        function show(content) {
            if (panel === null) {
                return;
            }
            if (!panelVisible) {
                panelVisible = true;
                panel.style.display = 'block';
            }
            panel.textContent = content;
        }

        return {
            install,
            uninstall,
            show,
            hide
        }
    })();


    // 缓冲区内容最大尺寸
    let bufSize = 0;
    // 缓冲区内容
    let buf = '';
    // 注册的所有指令
    let registeredCommands = [];
    /**
     * keypress callback
     * @param {Event} e 
     * @returns 
     */
    function eventCallback(e) {
        // 忽略页面中INPUT与TEXTAREA元素内的输入
        const nodeName = e.target.nodeName;
        if (nodeName === 'INPUT' || nodeName === 'TEXTAREA') {
            return;
        }
        // 将按键内容添加到缓冲区
        buf += e.key;
        // 裁剪缓冲区
        if (buf.length > bufSize) {
            buf = buf.substring(buf.length - bufSize);
        }

        // 显示panel
        PanelControl.show(buf);
        // 延迟关闭panel
        PanelControl.hide();

        // 遍历注册的command进行回调调用
        for (const cb of registeredCommands) {
            if (buf.endsWith(cb.cmd)) {
                cb.callback.call(null);
                return;
            }
        }
    }
    window.addEventListener('keypress', eventCallback);


    const SecretCommand = Object.create(null);

    /**
     * 绑定指令
     * @param {string} cmd 指令文本
     * @param {Function} callback 回调函数
     */
    SecretCommand.on = function(cmd, callback) {
        registeredCommands.push({ cmd, callback });
        // 重新定义缓冲区尺寸
        if (cmd.length > bufSize) {
            bufSize = cmd.length;
        }
    }
    /**
     * 解除绑定
     * @param {string} cmd 指令文本
     */
    SecretCommand.off = function(cmd) {
        registeredCommands = registeredCommands.filter(v => v.cmd !== cmd);
        // 对其排序并重新定义缓冲区尺寸
        registeredCommands.sort((a, b) => b.cmd.length - a.cmd.length);
        bufSize = registeredCommands.length > 0 ? registeredCommands[0].cmd.length : 0;
    }

    /**
     * 启用panel
     */
    SecretCommand.enablePanel = function() {
        PanelControl.install();
    }
    /**
     * 禁用panel
     */
    SecretCommand.disablePanel = function() {
        PanelControl.uninstall();
    }

    window.SecretCommand = SecretCommand;
})();